package com.guaigen.train.generator.gen;

import cn.hutool.core.util.StrUtil;
import com.guaigen.train.member.enums.PassengerTypeEnum;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class EnumGenerator {

    static String path = "web/src/assets/js/enums.js";

    public static void main(String[] args) {
        StringBuffer bufferObject = new StringBuffer();
        StringBuffer bufferArray = new StringBuffer();
        long begin = System.currentTimeMillis();

        try {
            toJson(PassengerTypeEnum.class, bufferObject, bufferArray);

            StringBuffer buffer = bufferObject.append("\r\n").append(bufferArray);
            writeJs(buffer);
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("执行耗时：" + (end - begin) + "毫秒");
    }

    /**
     * 将给定的字符串缓冲区内容写入JavaScript文件
     *
     * @param buffer 要写入文件的字符串缓冲区
     * @throws RuntimeException 当文件操作出现异常时抛出运行时异常
     */
    private static void writeJs(StringBuffer buffer) {
        FileOutputStream out = null;
        try {
            // 创建文件输出流，准备写入文件
            out = new FileOutputStream(path);
            // 创建输出流编码为UTF-8的输出流写入器，用于写入字符数据
            OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8");
            // 打印文件路径以便确认写入位置
            System.out.println(path);
            // 将字符串缓冲区的内容写入文件
            osw.write(buffer.toString());
            // 关闭输出流写入器，释放资源
            osw.close();
        } catch (FileNotFoundException e) {
            // 当指定文件不存在时抛出运行时异常
            throw new RuntimeException(e);
        } catch (UnsupportedEncodingException e) {
            // 当指定的字符编码不被支持时抛出运行时异常
            throw new RuntimeException(e);
        } catch (IOException e) {
            // 当进行文件操作时发生IO异常时抛出运行时异常
            throw new RuntimeException(e);
        } finally {
            // 确保在离开方法前关闭文件输出流
            try {
                out.close();
            } catch (IOException e) {
                // 当关闭文件输出流操作发生IO异常时抛出运行时异常
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 将枚举类转换为JSON格式的字符串
     * 此方法用于生成枚举类的JSON对象和数组格式的字符串表示
     * 它通过反射调用枚举类的name、getDesc和getCode方法来获取枚举项的名称、描述和代码
     *
     * @param clazz 枚举类的Class对象
     * @param bufferObject 用于积累JSON对象格式字符串的StringBuffer对象
     * @param bufferArray 用于积累JSON数组格式字符串的StringBuffer对象
     * @throws NoSuchMethodException 如果枚举类没有对应的getDesc或getCode方法
     * @throws InvocationTargetException 如果在调用枚举类的方法时抛出异常
     * @throws IllegalAccessException 如果没有访问枚举类方法的权限
     */
    private static void toJson(Class clazz, StringBuffer bufferObject, StringBuffer bufferArray) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 将枚举类名转换为大写并去除"Enum"后缀，用作JSON对象的键
        String enumConst = StrUtil.toUnderlineCase(clazz.getSimpleName())
                .toUpperCase().replace("_ENUM", "");
        // 获取枚举类的所有枚举常量
        Object[] objects = clazz.getEnumConstants();
        // 获取枚举类的name方法，用于获取枚举项的名称
        Method name = clazz.getMethod("name");
        // 获取枚举类的getDesc方法，用于获取枚举项的描述
        Method getDesc = clazz.getMethod("getDesc");
        // 获取枚举类的getCode方法，用于获取枚举项的代码
        Method getCode = clazz.getMethod("getCode");

        // 构建JSON对象格式的字符串
        bufferObject.append(enumConst).append("={");
        for (int i = 0; i < objects.length; i++) {
            Object obj = objects[i];
            // 拼接枚举项的名称、代码和描述到bufferObject中
            bufferObject.append(name.invoke(obj)).append(":{code:\"").append(getCode.invoke(obj)).append("\", desc:\"").append(getDesc.invoke(obj)).append("\"}");
            if (i < objects.length - 1) {
                bufferObject.append(",");
            }
        }
        bufferObject.append("};\r\n");

        // 构建JSON数组格式的字符串
        bufferArray.append(enumConst).append("_ARRAY=[");
        for (int i = 0; i < objects.length; i++) {
            Object obj = objects[i];
            // 拼接枚举项的代码和描述到bufferArray中
            bufferArray.append("{code:\"").append(getCode.invoke(obj)).append("\", desc:\"").append(getDesc.invoke(obj)).append("\"}");
            if (i < objects.length - 1) {
                bufferArray.append(",");
            }
        }
        bufferArray.append("];\r\n");
    }
}
